home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 019a / tde10src.zip / BLOCK.C next >
C/C++ Source or Header  |  1991-06-05  |  49KB  |  1,399 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - block commands module
  10.  * Purpose: This file contains all the commands than manipulate blocks.
  11.  * File:    block.c
  12.  * Author:  Douglas Thomson
  13.  * System:  this file is intended to be system-independent
  14.  * Date:    October 1, 1989
  15.  */
  16. /*********************  end of original comments   ********************/
  17.  
  18. /*
  19.  * The block routines have been EXTENSIVELY rewritten.  I am not very fond of
  20.  * stream blocks.  This editor uses LINE blocks and BLOCK blocks.  That is,
  21.  * one may either mark entire lines or column blocks.  Block operations are
  22.  * done in place.  There are no paste and cut buffers.  In limited memory
  23.  * situations, larger block operations can be carried out.  Block operations
  24.  * can be done within or across files.  One disadvantage of not using buffers
  25.  * is that block operations can be slow.  The most complicated routine in
  26.  * this editor is by far "move_copy_delete_overlay_block( window, action )".
  27.  * I put some comments in, but it can be hard to understand.
  28.  *
  29.  * Maybe in the next version I'll use buffers to speed up block operations.
  30.  *
  31.  * New editor name:  tde, the Thomson-Davis Editor.
  32.  * Author:           Frank Davis
  33.  * Date:             June 5, 1991
  34.  *
  35.  * This modification of Douglas Thomson's code is released into the
  36.  * public domain, Frank Davis.  You may distribute it freely.
  37.  */
  38.  
  39. #include "tdestr.h"
  40. #include "common.h"
  41. #include "tdefunc.h"
  42. #include "define.h"
  43.  
  44.  
  45. /*
  46.  * Name:    mark_block
  47.  * Purpose: To record the position of the start of the block in the file.
  48.  * Date:    June 5, 1991
  49.  * Passed:  window: information required to access current window
  50.  *          type: type of block LINE or BLOCK
  51.  * Notes:   Assume the user will mark begin and end of a block in either
  52.  *           line mode or column mode.  If the user mixes type, then block
  53.  *           type defaults to LINE.
  54.  */
  55. void mark_block( window, type )
  56. windows *window;
  57. int type;
  58. {
  59. file_infos *file;     /* temporary file variable */
  60. int num;
  61. long lnum;
  62.  
  63.    if (g_status.marked == FALSE) {
  64.       g_status.marked = TRUE;
  65.       g_status.marked_file = window->file_info;
  66.    }
  67.    file = window->file_info;
  68.    g_status.marked_window = window;
  69.  
  70.    /*
  71.     * define blocks for only one file.  it is ok to modify blocks in any window
  72.     * pointing to original marked file.
  73.     */
  74.    if (file == g_status.marked_file) {
  75.  
  76.       /*
  77.        * mark beginning and ending column reguardless of block mode.
  78.        */
  79.       if (file->block_type == NOTMARKED) {
  80.          file->block_ec  = file->block_bc = window->rcol;
  81.          file->block_er  = file->block_br = window->rline;
  82.       } else {
  83.          file->block_ec = window->rcol;
  84.          file->block_er = window->rline;
  85.  
  86.          /*
  87.           * if user marks ending line less than beginning line then switch
  88.           */
  89.          if (file->block_er < file->block_br) {
  90.             lnum = file->block_er;
  91.             file->block_er = file->block_br;
  92.             file->block_br = lnum;
  93.          }
  94.  
  95.          /*
  96.           * if user marks ending column less than beginning column then switch
  97.           */
  98.          if (file->block_ec < file->block_bc) {
  99.             num = file->block_ec;
  100.             file->block_ec = file->block_bc;
  101.             file->block_bc = num;
  102.          }
  103.       }
  104.  
  105.       /*
  106.        * block type in now defined.  if user mixes block type then default to
  107.        * LINE block.
  108.        */
  109.       if (file->block_type == NOTMARKED)
  110.          file->block_type = type;
  111.       else if (file->block_type == BLOCK && type == LINE)
  112.          file->block_type = LINE;
  113.       window->dirty = GLOBAL;
  114.       redraw_screen( window );
  115.    }
  116. }
  117.  
  118. /*
  119.  * Name:    unmark_block
  120.  * Purpose: To set all block information to NULL or 0
  121.  * Date:    June 5, 1991
  122.  * Passed:  window: information required to access current window
  123.  * Notes:   Reset all block variables if marked, otherwise return.
  124.  *           If a block is unmarked then redraw the screen(s).
  125.  */
  126. void unmark_block( window )
  127. windows *window;
  128. {
  129. file_infos *marked_file;
  130.  
  131.    if (g_status.marked == TRUE) {
  132.       marked_file              = g_status.marked_file;
  133.       g_status.marked          = FALSE;
  134.       g_status.marked_file     = NULL;
  135.       g_status.marked_window   = NULL;
  136.       marked_file->block_start = NULL;
  137.       marked_file->block_end   = NULL;
  138.       marked_file->block_bc    = marked_file->block_ec = 0;
  139.       marked_file->block_br    = marked_file->block_er = 0l;
  140.       if (marked_file->block_type) {
  141.          window->dirty = GLOBAL;
  142.          redraw_screen( window );
  143.       }
  144.       marked_file->block_type  = NOTMARKED;
  145.    }
  146. }
  147.  
  148. /*
  149.  * Name:    restore_marked_block
  150.  * Purpose: To restore block beginning and ending row after an editing function
  151.  * Date:    June 5, 1991
  152.  * Passed:  window: information required to access current window
  153.  * Notes:   If a change has been made before the marked block then the
  154.  *           beginning and ending row need to be adjusted by the number of
  155.  *           lines added or subtracted from file.
  156.  */
  157. void restore_marked_block( window, net_change )
  158. windows *window;
  159. int net_change;
  160. {
  161. file_infos *marked_file;
  162. long length;
  163.  
  164.    if (g_status.marked == TRUE && net_change != 0) {
  165.       marked_file = g_status.marked_file;
  166.       length = marked_file->length;
  167.  
  168.       /*
  169.        * restore is needed only if a block is defined and window->file_info is
  170.        * same as marked file and there was a net change in file length.
  171.        */
  172.       if (marked_file == window->file_info) {
  173.  
  174.          /*
  175.           * if cursor is before marked block then adjust block by net change.
  176.           */
  177.          if (marked_file->block_br > window->rline) {
  178.             marked_file->block_br += net_change;
  179.             marked_file->block_er += net_change;
  180.             window->dirty = GLOBAL;
  181.          /*
  182.           * if cursor is somewhere in marked block don't restore, do redisplay
  183.           */
  184.          } else if (marked_file->block_er >= window->rline)
  185.             window->dirty = GLOBAL;
  186.  
  187.          /*
  188.           * check for lines of marked block beyond end of file
  189.           */
  190.          if (marked_file->block_br > length)
  191.             unmark_block( window );
  192.          else if (marked_file->block_er > length) {
  193.             marked_file->block_er = length;
  194.             window->dirty = GLOBAL;
  195.          }
  196.       }
  197.    }
  198. }
  199.  
  200. /*
  201.  * Name:    prepare_block
  202.  * Purpose: To prepare a window/file for a block read, move or copy.
  203.  * Date:    June 5, 1991
  204.  * Passed:  window: current window
  205.  *          file: pointer to file information.
  206.  *          text_line: pointer to line in file to prepare.
  207.  *          lend: line length.
  208.  *          bc: beginning column of BLOCK.
  209.  * Notes:   The main complication is that the cursor may be beyond the end
  210.  *           of the current line, in which case extra padding spaces have
  211.  *           to be added before the block operation can take place.
  212.  *           This only occurs in BLOCK operations.
  213.  */
  214. int prepare_block( window, file, text_line, lend, bc )
  215. windows *window;
  216. file_infos *file;
  217. text_ptr text_line;
  218. int lend, bc;
  219. {
  220. text_ptr source;        /* source for block moves */
  221. text_ptr dest;          /* destination for block moves */
  222. int pad, i;             /* amount of padding to be added */
  223. int number;             /* number of characters for block moves */
  224. int prompt_line;
  225.  
  226.    prompt_line = window->bottom_line;
  227.    copy_line( text_line, prompt_line );
  228.  
  229.    /*
  230.     * work out how much padding is required to extend the current
  231.     *  line to the cursor position
  232.     */
  233.  
  234.    pad = bc + 1 - lend;
  235.  
  236.    /*
  237.     * make room for the padding spaces
  238.     */
  239.    source = g_status.line_buff + lend;
  240.    dest = source + pad;
  241.    number = pad + 1;
  242.    hw_move( dest, source, number );
  243.  
  244.    /*
  245.     * insert the padding spaces
  246.     */
  247.    for (i=pad; i>0; i--)
  248.       *source++ = ' ';
  249.    un_copy_line( text_line, prompt_line );
  250.    return( pad );
  251. }
  252.  
  253.  
  254. /*
  255.  * Name:    pad_dest_line
  256.  * Purpose: To prepare a window/file for a block move or copy.
  257.  * Date:    June 5, 1991
  258.  * Passed:  window: current window
  259.  *          file: pointer to file information.
  260.  *          dest_line: pointer to line in file to prepare.
  261.  * Notes:   We are doing a BLOCK action (except DELETE).   We have come to the
  262.  *          end of the file and have no more lines.  All this routine does
  263.  *          is add a blank line to file.
  264.  */
  265. void pad_dest_line( window, dest_file, dest_line )
  266. windows *window;
  267. file_infos *dest_file;
  268. text_ptr dest_line;
  269. {
  270. int prompt_line;
  271.  
  272.    prompt_line = window->bottom_line;
  273.    /*
  274.     * put linefeed in line_buff. dest_line should be pointing to
  275.     * file->end_text - 1.  since we inserted line feed, increment file length.
  276.     */
  277.    g_status.line_buff[0] = '\n';
  278.    g_status.line_buff[1] = CONTROL_Z;
  279.    un_copy_line( dest_line, prompt_line );
  280.    ++dest_file->length;
  281. }
  282.  
  283.  
  284. /*
  285.  * Name:    move_copy_delete_overlay_block
  286.  * Purpose: Master BLOCK or LINE routine.
  287.  * Date:    June 5, 1991
  288.  * Passed:  window: information required to access current window
  289.  *          action: action to take on a marked block
  290.  * Notes:   Operations on BLOCKs or LINES require several common operations.
  291.  *           All require finding the beginning and ending marks.  The
  292.  *           big differences are whether to delete the source block, copy the
  293.  *           source block, or leave the source block marked.
  294.  *          This routine will handle block operations across files.  Since one
  295.  *           must determine the relationship of source and destination blocks
  296.  *           within a file, it is relatively easy to expand this relationship
  297.  *           across files.  There are several caveats.  Most deal with the
  298.  *           difference between LINE and BLOCK operations others deal with
  299.  *           differences between operations within a file and operations
  300.  *           across files.
  301.  *          This is probably the most complicated routine in the editor.  It
  302.  *           is not easy to understand.
  303.  */
  304. void move_copy_delete_overlay_block( window, action )
  305. windows *window;
  306. int action;
  307. {
  308. windows *source_window; /* source window for block moves */
  309. text_ptr source;        /* source for block moves */
  310. text_ptr dest;          /* destination for block moves */
  311. text_ptr p;             /* temporary text pointer */
  312. long number;            /* number of characters for block moves */
  313. int lens;               /* length of source line */
  314. int lend;               /* length of destination line */
  315. int add;                /* characters being added from another line */
  316. int block_len;          /* length of the block */
  317. text_ptr block_start;   /* start of block in file */
  318. text_ptr block_end;
  319. char block_buff[BUFF_SIZE+2];
  320. int prompt_line;
  321. int same;               /* are these files the same */
  322. int source_first;       /* is source file lower in memory than dest */
  323. file_infos *source_file, *dest_file;
  324. int rcol, bc, ec;       /* temporary column variables */
  325. int xbc, xec;           /* temporary column variables */
  326. long rline;             /* temporary real line variable */
  327. long br, er, li;        /* temporary line variables */
  328. long dest_add;          /* number of bytes added to destination file */
  329. long source_sub;        /* number of bytes sub from source file */
  330. long diff;
  331. unsigned long block_size;
  332. int block_type;
  333. int fill_char;
  334. int fill_pad;           /* number of padding required for FILL or OVERLAY */
  335.  
  336.    /*
  337.     * initialze block variables
  338.     */
  339.    source_window = g_status.marked_window;
  340.    prompt_line = window->bottom_line;
  341.    dest_file = window->file_info;
  342.    source_file = g_status.marked_file;
  343.    check_block( window );
  344.    if (g_status.marked == FALSE)
  345.       return;
  346.    block_start = source_file->block_start;
  347.    block_end = source_file->block_end;
  348.    block_type = source_file->block_type;
  349.    dest = window->cursor = cpf( window->cursor );
  350.    rline = window->rline;
  351.  
  352.    /*
  353.     * if this is a LINE action, put the text below the current line
  354.     */
  355.    if (block_type == LINE && action != DELETE)
  356.       if ((p = find_next( dest )) != NULL)
  357.          dest = p;
  358.    /*
  359.     * must find out if source and destination file are the same.
  360.     * it don't matter with FILL and DELETE - those actions only modify the
  361.     * source file.
  362.     */
  363.    same = FALSE;
  364.    if (action == FILL) {
  365.       if (block_type == BLOCK) {
  366.          if (get_block_fill_char( window, &fill_char ) == ERROR)
  367.             return;
  368.          dest = block_start;
  369.          same = TRUE;
  370.       } else {
  371.          error( WARNING, prompt_line, "can only fill column blocks" );
  372.          return;
  373.       }
  374.    }
  375.    if (source_file == dest_file && action != DELETE && action != FILL) {
  376.       same = TRUE;
  377.       if (block_type == BLOCK && action == MOVE) {
  378.          if (rline == dest_file->block_br  &&
  379.               (window->rcol >= dest_file->block_bc &&
  380.                window->rcol <= dest_file->block_ec))
  381.              /*
  382.               * a block moved to within the block itself has no effect
  383.               */
  384.             return;
  385.       } else if (block_type == LINE) {
  386.          if (rline >= dest_file->block_br && rline <= dest_file->block_er) {
  387.              /*
  388.               * if COPYing or KOPYing within the block itself, reposition the
  389.               * destination to the next line after the block (if it exists)
  390.               */
  391.             if (action == COPY || action == KOPY) {
  392.                dest = cpf( block_end );
  393.                dest = find_next( dest );
  394.                if (dest == NULL)
  395.                   return;
  396.              /*
  397.               * a block moved to within the block itself has no effect
  398.               */
  399.             } else if (action == MOVE)
  400.                return;
  401.          }
  402.       }
  403.    }
  404.  
  405.    /*
  406.     * set up Beginning Column, Ending Column, Beginning Row, Ending Row
  407.     */
  408.    bc = source_file->block_bc;
  409.    ec = source_file->block_ec;
  410.    br = source_file->block_br;
  411.    er = source_file->block_er;
  412.  
  413.    /*
  414.     * if we are BLOCK FILLing, beginning column is bc, not the column of cursor
  415.     */
  416.    if (action == FILL)
  417.      rcol = bc;
  418.    else
  419.       rcol = window->rcol;
  420.    dest_add = source_sub = 0;
  421.  
  422.    /*
  423.     * must know if source of block is before or after destination
  424.     */
  425.    source_first = FALSE;
  426.    if (ptoul( dest ) > ptoul( source_file->block_start ))
  427.       source_first = TRUE;
  428.    if (same && block_type == BLOCK) {
  429.       if ( rline >= br)
  430.          source_first = TRUE;
  431.    }
  432.  
  433.    /*
  434.     * work out how much has to be moved
  435.     */
  436.    if (block_type == BLOCK) {
  437.       block_size = ((ec+1) - bc) * ((er+1) - br);
  438.       if (action != DELETE)
  439.          block_size += ((rcol+1) * ((er+1) - br));
  440.       else
  441.          block_size = 0;
  442.    } else if (block_type == LINE) {
  443.       if (action == COPY || action == KOPY)
  444.          block_size = ptoul( block_end ) - ptoul( block_start );
  445.       else
  446.          block_size = 0;
  447.    } else
  448.       return;
  449.  
  450.    /*
  451.     * check that there is room to add block to file
  452.     */
  453.    if (ptoul( g_status.end_mem ) + block_size >= ptoul( g_status.max_mem )) {
  454.       error( WARNING, prompt_line, "not enough memory for block" );
  455.       return;
  456.    }
  457.  
  458.    /*
  459.     * 1. can't create lines greater than g_display.line_length
  460.     * 2. if we are FILLing a BLOCK - fill block buff once right here
  461.     * 3. only allow overlaying BLOCKs
  462.     */
  463.    if (block_type == BLOCK) {
  464.       block_len = (ec+1) - bc;
  465.       if (action != DELETE && action != FILL) {
  466.          if (rcol + block_len > g_display.line_length) {
  467.             error( WARNING, prompt_line, "line would be too long" );
  468.             return;
  469.          }
  470.       } else if (action == FILL)
  471.          block_fill( block_buff, fill_char, block_len );
  472.    } else {
  473.       block_len = 0;
  474.       if (action == OVERLAY) {
  475.          error( WARNING, prompt_line, "can only overlay blocks" );
  476.          return;
  477.       }
  478.    }
  479.  
  480.    /*
  481.     * all block actions go forward thru file - check those pointers
  482.     */
  483.    source = cpf( block_start );
  484.    dest = cpf( dest );
  485.    for (li=br; li<=er; li++) {
  486.       lens = linelen( source );
  487.       lend = linelen( dest );
  488.  
  489.       /*
  490.        * if we are doing a BLOCK action and both the source and
  491.        * destination are 0 then we have nothing to do.  all LINE actions
  492.        * require processing.
  493.        */
  494.       if (lens != 0 || lend != 0 || block_type == LINE) {
  495.  
  496.          /*
  497.           * do actions that may require adding to file
  498.           */
  499.          if (action==MOVE || action==COPY || action==KOPY || action==FILL ||
  500.              action == OVERLAY) {
  501.             if (action != FILL) {
  502.                xbc = bc;
  503.                xec = ec;
  504.                if (action != OVERLAY  && block_type == BLOCK && same) {
  505.                   if (rcol < bc && rline > br && rline <=er)
  506.                      if (li >= rline) {
  507.                         xbc = bc + block_len;
  508.                         xec = ec + block_len;
  509.                      }
  510.                }
  511.                load_buff( block_buff, source, xbc, xec, block_type );
  512.             }
  513.             add = 0;
  514.             if (block_type == LINE) {
  515.                add = lens;
  516.                if (source[lens] == '\n')
  517.                   ++add;
  518.             } else if (block_type == BLOCK && lend < (rcol+1))
  519.                add = prepare_block( window, dest_file, dest, lend, rcol );
  520.             fill_pad = copy_buff_2file( window, block_buff, dest, rcol,
  521.                              block_len, block_type, action );
  522.             if (action == FILL || action == OVERLAY)
  523.                dest_add += fill_pad + add;
  524.             else
  525.                dest_add += block_len + add;
  526.             if (source_first == FALSE && action != FILL) {
  527.                if (action == OVERLAY)
  528.                   source = addltop( fill_pad + add, source );
  529.                else
  530.                   source = addltop( block_len + add, source );
  531.                source = cpf( source );
  532.             }
  533.             if (block_type == LINE && (action == COPY || action == KOPY)) {
  534.                ++dest_file->length;
  535.             }
  536.          }
  537.  
  538.          /*
  539.           * do actions that may require deleting from file
  540.           */
  541.          if (action == MOVE || action == DELETE) {
  542.             if ((block_type == BLOCK && lens >= (bc + 1)) ||
  543.                 block_type == LINE) {
  544.                add = block_len;
  545.                xbc = bc;
  546.                if (block_type == BLOCK) {
  547.                   if (lens <= (ec + 1))
  548.                      add = lens - bc;
  549.                   if (same && action == MOVE) {
  550.                      if (rcol < bc && rline >= br && rline <=er)
  551.                         if (li >= rline)
  552.                            xbc = bc + block_len;
  553.                   }
  554.                } else {
  555.                   add = lens;
  556.                   if (source[lens] == '\n') {
  557.                      ++add;
  558.                      if (action == DELETE)
  559.                         --source_file->length;
  560.                   }
  561.                }
  562.                delete_blocked_block( source_window, source, xbc, add,
  563.                                      block_type, prompt_line );
  564.                if (source_first == TRUE) {
  565.                   if (block_type == LINE || (block_type == BLOCK &&
  566.                       ptoul( dest ) != ptoul( source))) {
  567.                      dest = addltop( -add, dest );
  568.                      dest = cpf( dest );
  569.                   }
  570.                }
  571.                source_sub += add;
  572.             }
  573.          }
  574.       }
  575.  
  576.       /*
  577.        * if we are DELETEing or MOVEing blocks in LINE mode, the source
  578.        * is already pointing at next line to process because we just deleted
  579.        * the current source line.
  580.        * if we are doing any BLOCK action we need to move the source pointer
  581.        * to the next line.
  582.        */
  583.       if ((action != DELETE && action != MOVE && block_type == LINE) ||
  584.           block_type == BLOCK)
  585.          source = find_next( source );
  586.  
  587.       /*
  588.        * if we are doing any action other than DELETE, we need to move
  589.        * the destination to the next line in marked block.
  590.        * if we are in BLOCK mode, we may need to pad the end of the file
  591.        * with a blank line before we process the next line.
  592.        */
  593.       if (action != DELETE) {
  594.          p = find_next( dest );
  595.          if (block_type == LINE)
  596.             dest = p;
  597.          else {
  598.             if (p != NULL)
  599.                dest = p;
  600.             else {
  601.                diff = 0l;
  602.                if (source_first || same) {
  603.                   if (action == MOVE)
  604.                      diff = dest_add - source_sub;
  605.                   else
  606.                      diff = dest_add + source_sub;
  607.                } else
  608.                   diff = dest_add;
  609.                p = addltop( diff-1, dest_file->end_text);
  610.                pad_dest_line( window, dest_file, p );
  611.                dest = find_next( dest );
  612.                ++dest_add;
  613.             }
  614.          }
  615.       }
  616.    }
  617.  
  618.    /*
  619.     * the block action is now complete.  restore all the start_text and
  620.     * end_text pointers for all open files.
  621.     */
  622.    if (action == MOVE || action == DELETE)
  623.       restore_start_end( dest_file, source_file, dest_add, -source_sub,
  624.                          source_first );
  625.    else
  626.       restore_start_end( dest_file, source_file, dest_add, source_sub,
  627.                          source_first );
  628.    /*
  629.     * restore all cursors in all windows
  630.     */
  631.    restore_cursors( dest_file, source_file );
  632.    dest_file->modified = TRUE;
  633.    if (action == MOVE  ||  action == DELETE || action == FILL)
  634.       source_file->modified = TRUE;
  635.    window->dirty = GLOBAL;
  636.  
  637.    /*
  638.     * unless we are doing a KOPY, FILL, or OVERLAY we need to unmark the
  639.     * block.  if we just did a KOPY, the beginning and ending may have
  640.     * changed.  so, we must reajust beginning and ending rows.
  641.     */
  642.    if (action == KOPY) {
  643.       if (same && !source_first && block_type == LINE) {
  644.          number = (er+1) - br;
  645.          source_file->block_br += number;
  646.          source_file->block_er += number;
  647.       } else if (same && !source_first && window->rline == br &&
  648.                  block_type == BLOCK) {
  649.          add = (ec+1) - bc;
  650.          source_file->block_bc += add;
  651.          source_file->block_ec += add;
  652.       }
  653.       redraw_screen( window );
  654.    } else if (action != FILL && action != OVERLAY)
  655.       unmark_block( window );
  656.    show_avail_mem( );
  657. }
  658.  
  659.  
  660. /*
  661.  * Name:    load_buff
  662.  * Purpose: copy the contents of a line in a BLOCK to the block buffer.
  663.  * Date:    June 5, 1991
  664.  * Passed:  block_buff: local buffer for block moves
  665.  *          source:  source line in file
  666.  *          bc:  beginning column of BLOCK. used only in BLOCK operations.
  667.  *          ec:  ending column of BLOCK. used only in BLOCK operations.
  668.  *          block_type:  LINE or BLOCK
  669.  * Notes:   If the block is marked in LINE mode, copy the the line to the
  670.  *          block buffer.  If the block is marked in BLOCK mode, there are
  671.  *          several things to take care of.   1) The BLOCK begins and ends
  672.  *          within a line - just copy the blocked characters to the block buff.
  673.  *          2) the BLOCK begins within a line but ends past the eol - copy
  674.  *          all the characters within the line to the block buff then fill with
  675.  *          padding.  3) the BLOCK begins and ends past eol - fill entire
  676.  *          block buff with padding.
  677.  */
  678. void load_buff( block_buff, source, bc, ec, block_type )
  679. char *block_buff;
  680. text_ptr source;
  681. int bc, ec, block_type;
  682. {
  683. int len, pad, avlen, i;
  684.  
  685.    len = linelen( source );
  686.    if (block_type == LINE) {
  687.       if (source[len] == '\n')
  688.         ++len;
  689.       for (i=len; i>0; i--)
  690.          *block_buff++ = *source++;
  691.    } else {
  692.       /*
  693.        * block start may be past eol
  694.        */
  695.       if (len < ec + 1) {
  696.          /*
  697.           * does block start past eol? - fill with pad
  698.           */
  699.          if (len < bc) {
  700.             pad = (ec + 1) - bc;
  701.             for (i=pad; i>0; i--)
  702.                *block_buff++ = ' ';
  703.          } else {
  704.             /*
  705.              * block ends past eol - fill with pad
  706.              */
  707.             pad = (ec + 1) - len;
  708.             avlen = len - bc;
  709.             source = source + bc;
  710.             for (i=avlen; i>0; i--)
  711.                *block_buff++ = *source++;
  712.             for (i=pad; i>0; i--)
  713.                *block_buff++ = ' ';
  714.          }
  715.       } else {
  716.          /*
  717.           * block is within line - copy block to buffer
  718.           */
  719.          avlen = (ec + 1) - bc;
  720.          source = source + bc;
  721.          for (i=avlen; i>0; i--)
  722.             *block_buff++ = *source++;
  723.       }
  724.    }
  725.    *block_buff++ = CONTROL_Z;
  726.    *block_buff = '\0';
  727. }
  728.  
  729.  
  730. /*
  731.  * Name:    copy_buff_2file
  732.  * Purpose: copy the contents of block buffer to destination file
  733.  * Date:    June 5, 1991
  734.  * Returns: number of bytes added to file
  735.  * Passed:  window:  current window
  736.  *          block_buff:  local buffer for moves
  737.  *          dest:  pointer to destination line in destination file
  738.  *          rcol:  if in BLOCK mode, destination column in destination file
  739.  *          block_len:  if in BLOCK mode, width of block to copy
  740.  *          block_type: type of block mode - BLOCK or LINE
  741.  * Notes:   If in BLOCK mode, the destination line has already been prepared.
  742.  *          Just copy the BLOCK buffer to the destination line.
  743.  *          If in LINE mode, make room for the line and copy it to destination.
  744.  */
  745. int  copy_buff_2file( window, block_buff, dest, rcol, block_len, block_type,
  746.                       action )
  747. windows *window;
  748. char *block_buff;
  749. text_ptr dest;
  750. int rcol, block_len, block_type, action;
  751. {
  752. text_ptr s;
  753. text_ptr d;
  754. long number;
  755. int i;
  756. int prompt_line;
  757. int rc;
  758.  
  759.    rc = 0;
  760.    prompt_line = window->bottom_line;
  761.    if (block_type == BLOCK) {
  762.       copy_line( dest, prompt_line );
  763.       s = g_status.line_buff + rcol;
  764.  
  765.       /*
  766.        * s is pointing to location to perform BLOCK operation.  If we do a
  767.        * FILL or OVERLAY, we do not necessarily add any extra space.  If the
  768.        * line does not extend all the thru the BLOCK then we add.
  769.        * we always add space when we COPY, KOPY, or MOVE
  770.        */
  771.       if (action == FILL || action == OVERLAY) {
  772.          i = linelen( s );
  773.          if (i < block_len) {
  774.             rc = block_len - i;
  775.             d = s + rc;
  776.             number = block_len + 1 + linelen( g_status.line_buff ) - rcol;
  777.             hw_move( d, s, number );
  778.          }
  779.       } else {
  780.          d = s + block_len;
  781.          number = block_len + 1 + linelen( g_status.line_buff ) - rcol;
  782.          hw_move( d, s, number );
  783.       }
  784.       d = g_status.line_buff;
  785.       for (i=block_len; i>0; i--)
  786.          *s++ = *block_buff++;
  787.       un_copy_line( dest, prompt_line );
  788.    } else {
  789.  
  790.       /*
  791.        * when doing LINE operation, always make room for line operation.
  792.        * the LINE used for COPY, KOPY, or MOVE is in the block_buff.
  793.        */
  794.       i = find_CONTROL_Z( block_buff );
  795.       s = dest;
  796.       d = s + i;
  797.       number = ptoul( g_status.end_mem ) - ptoul( dest );
  798.       hw_move( d, s, number );
  799.       g_status.end_mem = cpf( g_status.end_mem );
  800.       g_status.end_mem += i;
  801.       for (; i>0; i--)
  802.          *dest++ = *block_buff++;
  803.    }
  804.    return( rc );
  805. }
  806.  
  807.  
  808. /*
  809.  * Name:    block_fill
  810.  * Purpose: fill the block buffer with character
  811.  * Date:    June 5, 1991
  812.  * Passed:  block_buff:  local buffer for moves
  813.  *          fill_char:  fill character
  814.  * Notes:   fill block buffer with character until end of string
  815.  */
  816. void block_fill( block_buff, fill_char, block_len)
  817. char *block_buff;
  818. int fill_char;
  819. int block_len;
  820. {
  821.    memset( block_buff, fill_char, block_len );
  822.    *(block_buff+block_len) = CONTROL_Z;
  823. }
  824.  
  825.  
  826. /*
  827.  * Name:    restore_start_end
  828.  * Purpose: a file has been modified - must restore all start and end pointers
  829.  * Date:    June 5, 1991
  830.  * Passed:  dest_file:  pointer to destination file structure
  831.  *          source_file:  pointer to source file structure
  832.  *          dest_mod:  net modifications in the destination file
  833.  *          source_mod:  net modifications in the source file
  834.  *          source_first:  we must know which file is stored first in memory
  835.  * Notes:   Go through the file list and adjust the start_text and end_text
  836.  *          file pointers as needed.   There are several cases that must be
  837.  *          be considered.  1) destination file and source file could be the
  838.  *          same.  2) if the file pointer we're looking at is below both
  839.  *          the source and destination, no action is needed.  3) the file
  840.  *          we're looking at could be between the source and destination.
  841.  *          4) the file we're looking at could be either source or destination.
  842.  *          5) the file we're looking at could be past both source and dest.
  843.  *          Use unsigned longs to compare pointers.
  844.  */
  845. void restore_start_end( dest_file, source_file, dest_mod, source_mod,
  846.                         source_first )
  847. file_infos *dest_file, *source_file;
  848. long dest_mod, source_mod;
  849. int source_first;
  850. {
  851. int same;
  852. long net_mod;
  853. unsigned long sst;      /* source start_text */
  854. unsigned long dst;      /* destination start_text */
  855. unsigned long ost;      /* open_file start_text */
  856. file_infos *open_file;
  857.  
  858.    net_mod = dest_mod + source_mod;
  859.    sst = ptoul( source_file->start_text );
  860.    dst = ptoul( dest_file->start_text );
  861.    same = (sst == dst) ? TRUE : FALSE;
  862.    for (open_file=g_status.file_list; open_file != NULL;
  863.              open_file=open_file->next) {
  864.       sst = ptoul( source_file->start_text );
  865.       dst = ptoul( dest_file->start_text );
  866.       ost = ptoul( open_file->start_text );
  867.       if (ost == sst) {
  868.          if (same)
  869.             source_file->end_text = addltop( net_mod, source_file->end_text);
  870.          else if (source_first)
  871.             source_file->end_text = addltop( source_mod,
  872.                                              source_file->end_text);
  873.          else {
  874.             source_file->start_text = addltop( dest_mod,
  875.                                              source_file->start_text);
  876.             source_file->end_text = addltop( net_mod, source_file->end_text);
  877.          }
  878.       } else if (ost == dst) {
  879.          if (source_first) {
  880.             dest_file->start_text = addltop( source_mod,
  881.                                              dest_file->start_text);
  882.             dest_file->end_text = addltop( net_mod, dest_file->end_text);
  883.          } else
  884.             dest_file->end_text = addltop( dest_mod, dest_file->end_text);
  885.       } else if (ost > sst) {
  886.          if (ost < dst) {
  887.             open_file->start_text = addltop( source_mod,
  888.                                              open_file->start_text);
  889.             open_file->end_text = addltop( source_mod, open_file->end_text);
  890.          } else {
  891.             open_file->start_text = addltop( net_mod, open_file->start_text);
  892.             open_file->end_text = addltop( net_mod, open_file->end_text);
  893.          }
  894.       } else if (ost > dst) {
  895.          if (ost < sst) {
  896.             open_file->start_text = addltop( dest_mod, open_file->start_text);
  897.             open_file->end_text = addltop( dest_mod, open_file->end_text);
  898.          } else {
  899.             open_file->start_text = addltop( net_mod, open_file->start_text);
  900.             open_file->end_text = addltop( net_mod, open_file->end_text);
  901.          }
  902.       }
  903.    }
  904. }
  905.  
  906.  
  907. /*
  908.  * Name:    restore_cursors
  909.  * Purpose: a file has been modified - must restore all cursor pointers
  910.  * Date:    June 5, 1991
  911.  * Passed:  none
  912.  * Notes:   Go through the window list and adjust the cursor pointers
  913.  *          as needed.   This could be done by using the changes made by
  914.  *          the block actions, but it would be a real pain in the neck.
  915.  *          I chose to use the brute force approach.
  916.  */
  917. void restore_cursors( dest_file, source_file )
  918. file_infos *dest_file, *source_file;
  919. {
  920. windows *window;
  921. text_ptr p;
  922. file_infos *file;
  923. long beg_line, cur_line, test_line;
  924. unsigned long df, sf, f;
  925.  
  926.    df = ptoul( (text_ptr)dest_file );
  927.    sf = ptoul( (text_ptr)source_file );
  928.    window = g_status.window_list;
  929.    while (window != NULL) {
  930.       file = window->file_info;
  931.       f = ptoul( (text_ptr)file );
  932.       beg_line = 1;
  933.       cur_line = window->rline;
  934.       if (cur_line > file->length) {
  935.          file->end_text = cpb( file->end_text );
  936.          p = find_prev( file->end_text-1 );
  937.          if (p != NULL )
  938.             window->cursor = p;
  939.          else
  940.             window->cursor = file->start_text;
  941.          window->rline = file->length;
  942.          test_line = cur_line - file->length;
  943.          if (test_line < (long)(window->cline - (window->top_line - 1)))
  944.             window->cline -= test_line;
  945.       } else {
  946.          file->start_text = cpf( file->start_text );
  947.          for (p=file->start_text; p!=NULL && beg_line<cur_line; beg_line++)
  948.             p = find_next( p );
  949.          if (p != NULL )
  950.             window->cursor = p;
  951.          else {
  952.             window->cursor = file->start_text;
  953.             cur_line = file->length;
  954.          }
  955.          window->rline = cur_line;
  956.       }
  957.       if (window->rline < (window->cline - (window->top_line - 1)))
  958.          window->cline = window->rline + window->top_line - 1;
  959.       if ((f == df || f == sf) && window->visible )
  960.          show_size( window );
  961.       window = window->next;
  962.    }
  963. }
  964.  
  965.  
  966. /*
  967.  * Name:    delete_blocked_block
  968.  * Purpose: delete the marked text
  969.  * Date:    June 5, 1991
  970.  * Passed:  s_w:  source window
  971.  *          source:  pointer to line with block to delete
  972.  *          bc:  beginning column of block - BLOCK mode only
  973.  *          add:  number of characters in block to delete
  974.  *          block_type: type of block - BLOCK or LINE
  975.  *          prompt_line:  line to display error message if needed
  976.  * Notes:   If in BLOCK mode, just delete the block.  If in LINE mode delete
  977.  *          the whole line.
  978.  */
  979. void delete_blocked_block( s_w, source, bc, add, block_type, prompt_line )
  980. windows *s_w;
  981. text_ptr source;
  982. int bc, add, block_type, prompt_line;
  983. {
  984. text_ptr s;
  985. text_ptr d;
  986. int number;
  987.  
  988.    if (block_type == BLOCK) {
  989.       number = linelen( source );
  990.       copy_line( source, prompt_line );
  991.       s = g_status.line_buff + bc + add;
  992.       d = s - add;
  993.       number = number - bc + 2;
  994.       hw_move( d, s, number );
  995.    } else
  996.       *g_status.line_buff = CONTROL_Z;
  997.    un_copy_line( source, prompt_line );
  998. }
  999.  
  1000. /*
  1001.  * Name:    check_block
  1002.  * Purpose: To check that the block is still valid.
  1003.  * Date:    June 5, 1991
  1004.  * Passed:  window: information required to access current window
  1005.  * Notes:   After some editing, the marked block may not be valid.  For example,
  1006.  *          deleting all the lines in a block in another window.
  1007.  */
  1008. void check_block( window )
  1009. windows *window;
  1010. {
  1011. file_infos *file;
  1012.  
  1013.    file = g_status.marked_file;
  1014.    if (file == NULL || file->block_br > file->length)
  1015.       unmark_block( window );
  1016.    else {
  1017.       if (file->length < file->block_er)
  1018.          file->block_er = file->length;
  1019.       find_begblock( file );
  1020.       find_endblock( file );
  1021.    }
  1022. }
  1023.  
  1024.  
  1025. /*
  1026.  * Name:    find_begblock
  1027.  * Purpose: find the beginning line in file with marked block
  1028.  * Date:    June 5, 1991
  1029.  * Passed:  file: file containing marked block
  1030.  * Notes:   file->block_start contains starting line of marked block at end.
  1031.  */
  1032. void find_begblock( file )
  1033. file_infos *file;
  1034. {
  1035. text_ptr next;    /* start from beginning of file and go to end */
  1036. long i;           /* line counter */
  1037.  
  1038.    next = cpf( file->start_text );
  1039.    for (i=1; i<file->block_br && next != NULL; i++)
  1040.       next = find_next( next );
  1041.    if (next != NULL)
  1042.       file->block_start = next;
  1043. }
  1044.  
  1045.  
  1046. /*
  1047.  * Name:    find_endblock
  1048.  * Purpose: find the ending line in file with marked block
  1049.  * Date:    June 5, 1991
  1050.  * Passed:  file: file containing marked block
  1051.  * Notes:   If in LINE mode, file->block_end is set to end of line of last
  1052.  *          line in block.  If in BLOCK mode, file->block_end is set to
  1053.  *          beginning of last line in marked block.  If the search for the
  1054.  *          ending line of the marked block goes past the eof, set the
  1055.  *          ending line of the block to the last line in the file.
  1056.  */
  1057. void find_endblock( file )
  1058. file_infos *file;
  1059. {
  1060. text_ptr next;    /* start from beginning of file and go to end */
  1061. long i;           /* line counter */
  1062. int end_column;
  1063.  
  1064.    next = cpf( file->start_text );
  1065.    for (i=1; i<file->block_er && next != NULL; i++)
  1066.       next = find_next( next );
  1067.    if (next != NULL) {
  1068.       end_column = linelen( next );
  1069.       if (file->block_type == LINE)
  1070.          file->block_end = next + end_column;
  1071.       else
  1072.          file->block_end = next;
  1073.    } else {
  1074.       file->end_text = cpb( file->end_text );
  1075.       if (file->block_type == LINE)
  1076.          file->block_end = file->end_text - 1;
  1077.       else {
  1078.          next = find_prev( file->end_text - 1 );
  1079.          if (next != NULL)
  1080.             file->block_end = next;
  1081.          else
  1082.             file->block_end = file->end_text - 1;
  1083.       }
  1084.       file->block_er = file->length;
  1085.    }
  1086. }
  1087.  
  1088. /*
  1089.  * Name:    block_write
  1090.  * Purpose: To write the currently marked block to a disk file.
  1091.  * Date:    June 5, 1991
  1092.  * Passed:  window: information required to access current window
  1093.  * Notes:   If the file already exists, the user gets to choose whether
  1094.  *           to overwrite or append.
  1095.  */
  1096. void block_write( window )
  1097. windows *window;
  1098. {
  1099. int prompt_line;
  1100. int rc;
  1101. char buff[MAX_COLS+2]; /* buffer for char and attribute  */
  1102. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1103. text_ptr block_start;   /* start of block in file */
  1104. text_ptr block_end;     /* end of block in file */
  1105. file_infos *file;
  1106. int block_type;
  1107.  
  1108.    /*
  1109.     * make sure block is marked OK
  1110.     */
  1111.    check_block( window );
  1112.    if (g_status.marked == TRUE) {
  1113.       prompt_line = window->bottom_line;
  1114.       file        = window->file_info;
  1115.       block_start = file->block_start;
  1116.       block_end   = file->block_end;
  1117.       block_type  = file->block_type;
  1118.  
  1119.       /*
  1120.        * find out which file to write to
  1121.        */
  1122.       save_screen_line( 0, prompt_line, line_buff );
  1123.       if (get_name( "Filename: ", prompt_line, g_status.rw_name,
  1124.                     g_display.message_color ) == OK) {
  1125.          /*
  1126.           * if the file exists, find out whether to overwrite or append
  1127.           */
  1128.          if (hw_fattrib( g_status.rw_name ) != ERROR) {
  1129.             set_prompt( "File exists. Overwrite or Append? (o/a): ",
  1130.                          prompt_line );
  1131.             switch (get_oa( )) {
  1132.                case A_OVERWRITE :
  1133.                   hw_unlink( g_status.rw_name, prompt_line );
  1134.                   combine_strings( buff, "writing block to '",
  1135.                                    g_status.rw_name, "'" );
  1136.                   s_output( buff, prompt_line, 0, g_display.message_color );
  1137.                   rc = hw_save( g_status.rw_name, block_start, block_end,
  1138.                                 block_type, prompt_line );
  1139.                   if (rc == ERROR)
  1140.                      error( WARNING, prompt_line, "could not write block" );
  1141.                   break;
  1142.                case A_APPEND :
  1143.                   combine_strings( buff, "appending block to '",
  1144.                                    g_status.rw_name, "'" );
  1145.                   s_output( buff, prompt_line, 0, g_display.message_color );
  1146.                   rc = hw_append( g_status.rw_name, block_start, block_end,
  1147.                                   block_type, prompt_line );
  1148.                   if (rc == ERROR)
  1149.                      error( WARNING, prompt_line, "could not append block" );
  1150.                   break;
  1151.             }
  1152.          } else {
  1153.             combine_strings( buff, "writing block to '", g_status.rw_name,
  1154.                              "'" );
  1155.             s_output( buff, prompt_line, 0, g_display.message_color );
  1156.             if (hw_save( g_status.rw_name, block_start, block_end,
  1157.                          block_type, prompt_line ) == ERROR)
  1158.                error( WARNING, prompt_line, "could not write block" );
  1159.          }
  1160.       }
  1161.       restore_screen_line( 0, prompt_line, line_buff );
  1162.    }
  1163. }
  1164.  
  1165.  
  1166. /*
  1167.  * Name:    block_print
  1168.  * Purpose: Print an entire file or the currently marked block.
  1169.  * Date:    June 5, 1991
  1170.  * Passed:  window: information required to access current window
  1171.  */
  1172. void block_print( window )
  1173. windows *window;
  1174. {
  1175. char answer[MAX_COLS];  /* entire file or just marked block? */
  1176. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1177. int col;
  1178. int prompt_line;
  1179. text_ptr block_start;   /* start of block in file */
  1180. text_ptr block_end;     /* end of block in file */
  1181. file_infos *file;
  1182. int block_type;
  1183.  
  1184.    prompt_line = window->bottom_line;
  1185.    save_screen_line( 0, prompt_line, line_buff );
  1186.    /*
  1187.     * print entire file or just marked block?
  1188.     */
  1189.    strcpy( answer, "Print file or block? (f/b): " );
  1190.    col = strlen( answer );
  1191.    s_output( answer, prompt_line, 0, g_display.message_color );
  1192.    eol_clear( col, prompt_line, g_display.text_color );
  1193.    xygoto( col, prompt_line );
  1194.    col = 0;
  1195.    while (col != 'f' && col != 'F' && col != 'b' && col != 'B' && col != ESC)
  1196.       col = (col=getch()) != 0 ? col : getch() | 0x100;
  1197.    if (col != ESC) {
  1198.       file = window->file_info;
  1199.       if (col == 'f' || col == 'F') {
  1200.          strcpy( answer, "Printing file..." );
  1201.          block_start = file->start_text;
  1202.          block_end   = file->end_text - 1;
  1203.          block_type = NOTMARKED;
  1204.       } else if (col == 'b' || col == 'B') {
  1205.          check_block( window );
  1206.          if (g_status.marked == TRUE) {
  1207.             strcpy( answer, "Printing block..." );
  1208.             block_start = file->block_start;
  1209.             block_end   = file->block_end;
  1210.             block_type = file->block_type;
  1211.          } else
  1212.             col = ESC;
  1213.       }
  1214.       if (col != ESC) {
  1215.          col = strlen( answer );
  1216.          s_output( answer, prompt_line, 0, g_display.message_color );
  1217.          eol_clear( col, prompt_line, g_display.text_color );
  1218.          if (hw_print( block_start, block_end, block_type, prompt_line ))
  1219.             error( WARNING, prompt_line, "error in printing text" );
  1220.       }
  1221.    }
  1222.    restore_screen_line( 0, prompt_line, line_buff );
  1223. }
  1224.  
  1225.  
  1226. /*
  1227.  * Name:    get_block_fill_char
  1228.  * Purpose: get the character to fill marked block.
  1229.  * Date:    June 5, 1991
  1230.  * Passed:  window: information required to access current window
  1231.  *          c: address of character to fill block
  1232.  */
  1233. int  get_block_fill_char( window, c )
  1234. windows *window;
  1235. int *c;
  1236. {
  1237. char answer[MAX_COLS];  /* entire file or just marked block? */
  1238. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1239. int col;
  1240. int prompt_line;
  1241. int rc;
  1242.  
  1243.    rc = OK;
  1244.    prompt_line = window->bottom_line;
  1245.    save_screen_line( 0, prompt_line, line_buff );
  1246.    strcpy( answer, "Enter character to fill block (ESC to exit): " );
  1247.    s_output( answer, prompt_line, 0, g_display.message_color );
  1248.    col = strlen( answer );
  1249.    eol_clear( col, prompt_line, g_display.text_color );
  1250.    xygoto( col, prompt_line );
  1251.    col = (col=getch()) != 0 ? col : getch() | 0x100;
  1252.    if (col == ESC || col == RTURN)
  1253.       rc = ERROR;
  1254.    else
  1255.       *c = col;
  1256.    restore_screen_line( 0, prompt_line, line_buff );
  1257.    return( rc );
  1258. }
  1259.  
  1260.  
  1261. /*
  1262.  * Name:    block_expand_tabs
  1263.  * Purpose: Expand tabs in a marked block.
  1264.  * Date:    June 5, 1991
  1265.  * Passed:  window:  pointer to current window
  1266.  * Notes:   Tabs are expanded using the current tab interval.
  1267.  *          Lines are checked to make sure they are not too long.
  1268.  */
  1269. void block_expand_tabs( window )
  1270. windows *window;
  1271. {
  1272. int prompt_line;
  1273. int len;
  1274. int tab;
  1275. int tab_size;
  1276. int dirty;
  1277. int spaces;
  1278. int net_change;
  1279. text_ptr p;                     /* pointer to block line */
  1280. file_infos *file;
  1281. int block_type;
  1282. long num_block_lines, li;
  1283. int bc, ec, tc;
  1284. int i, j;
  1285. char exp_buff[BUFF_SIZE+2], *b, *q, *s, *d;
  1286.  
  1287.    /*
  1288.     * make sure block is marked OK
  1289.     */
  1290.    check_block( window );
  1291.    if (g_status.marked == TRUE) {
  1292.       prompt_line = window->bottom_line;
  1293.       dirty = FALSE;
  1294.       tab_size = g_status.tab_size;
  1295.       file  = window->file_info;
  1296.       bc = file->block_bc;
  1297.       ec = file->block_ec;
  1298.       p  = cpf( file->block_start );
  1299.       block_type = file->block_type;
  1300.       num_block_lines = file->block_er - (file->block_br - 1);
  1301.       for (li=num_block_lines; li>0; li--) {
  1302.          tab = FALSE;
  1303.          len = linelen( p );
  1304.          net_change = 0;
  1305.          if (block_type == BLOCK) {
  1306.             if (len > bc) {
  1307.                copy_line( p+bc, prompt_line);
  1308.                b = g_status.line_buff;
  1309.                for (j=0,i=bc; i<= ec && i<len; i++,j++)
  1310.                   exp_buff[j] = *b++;
  1311.                exp_buff[j] = CONTROL_Z;
  1312.                b = g_status.line_buff;
  1313.                i = ec <= len ? ec : len;
  1314.                i -= bc;
  1315.                s = b + i;
  1316.                j = linelen( s ) + 3;
  1317.                hw_move( b, s, j );
  1318.                b = exp_buff;
  1319.                for (b=exp_buff, i=bc+1; *b != CONTROL_Z; b++) {
  1320.                   if (*b == '\t') {
  1321.                      tab = TRUE;
  1322.                      spaces = i % tab_size;
  1323.                      if (spaces)
  1324.                         spaces = tab_size - spaces;
  1325.                      if (spaces) {
  1326.                         d = b + spaces;
  1327.                         j = linelen( b ) + 2;
  1328.                         hw_move( d, b, j );
  1329.                      }
  1330.                      for (j=0; j<=spaces; j++)
  1331.                         *(b+j) =  ' ';
  1332.                      net_change += spaces;
  1333.                      i += spaces + 1;
  1334.                      b += spaces;
  1335.                   } else
  1336.                      i++;
  1337.                }
  1338.                if (tab == TRUE) {
  1339.                   i = linelen( exp_buff );
  1340.                   j = len + net_change;
  1341.                   s = g_status.line_buff;
  1342.                   d = s + i;
  1343.                   hw_move( d, s, j );
  1344.                   for (q=s, b=exp_buff; *b != CONTROL_Z;)
  1345.                      *q++ = *b++;
  1346.                   un_copy_line( p+bc, prompt_line );
  1347.                }
  1348.             }
  1349.          } else if (block_type == LINE) {
  1350.             copy_line( p, prompt_line);
  1351.             for (s=g_status.line_buff, d=exp_buff; *s != CONTROL_Z;)
  1352.                *d++ = *s++;
  1353.             *d = CONTROL_Z;
  1354.             for (b=exp_buff, i=1; *b != CONTROL_Z; b++) {
  1355.                if (*b == '\t') {
  1356.                   tab = TRUE;
  1357.                   spaces = i % tab_size;
  1358.                   if (spaces)
  1359.                      spaces = tab_size - spaces;
  1360.                   if (spaces) {
  1361.                      d = b + spaces;
  1362.                      j = linelen( b ) + 2;
  1363.                      hw_move( d, b, j );
  1364.                   }
  1365.                   for (j=0; j<=spaces; j++)
  1366.                      *(b+j) =  ' ';
  1367.                   net_change += spaces;
  1368.                   i += spaces + 1;
  1369.                   b += spaces;
  1370.                } else
  1371.                   i++;
  1372.             }
  1373.             if (tab == TRUE) {
  1374.                for (s=exp_buff,d=g_status.line_buff; *s != CONTROL_Z;)
  1375.                   *d++ = *s++;
  1376.                *d = CONTROL_Z;
  1377.                un_copy_line( p, prompt_line );
  1378.             }
  1379.          }
  1380.          if (tab == TRUE) {
  1381.             if (ptoul( window->cursor ) > ptoul( p )) {
  1382.                window->cursor = cpf( window->cursor );
  1383.                window->cursor += net_change;
  1384.             }
  1385.             adjust_start_end( file, net_change );
  1386.             adjust_windows_cursor( window, (long)net_change, 0 );
  1387.             dirty = GLOBAL;
  1388.          }
  1389.          p = find_next( p );
  1390.       }
  1391.       if (dirty) {
  1392.          check_block( window );
  1393.          window->dirty = dirty;
  1394.          file->modified = TRUE;
  1395.          show_avail_mem( );
  1396.       }
  1397.    }
  1398. }
  1399.